package lablayer.view;

import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Panel;
import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
import lablayer.view.stat.ViewBoxBuffer;
import lablayer.view.state.StateFactory;
import lablayer.view.state.StateInterface;
import lablayer.view.additional.ToolPanel;
import javafx.geometry.Point2D;
import lablayer.model.LLNode;
import java.io.IOException;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.lang.Exception;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import java.lang.UnsupportedOperationException;
import lablayer.view.ViewMiddleValue;
import lablayer.view.ViewAccuracyAssessment;
import lablayer.view.ViewDifferenceBetween;
import lablayer.view.ViewIntervalBorders;

/**
 * @author Darkness
 */

public class ViewBox extends ViewComponent {
    public var width: Float;
    public var height: Float;
    var mainPanel: Panel;
    
    var viewComponentTranslateX: Float = 10.0;
    var viewComponentTranslateY: Float = 10.0;

    init {
        var state: StateInterface = StateFactory.getState();

        state.addState(StateInterface.COMPONENT_STATE);
        state.addState(StateInterface.LINK_STATE);
        ViewBoxBuffer.setViewBox(this);
    }

    override public function create(): javafx.scene.Node {
            this.mainPanel = Panel {
                layoutX: 0
                layoutY: 0
                width: bind this.width
                height: bind this.height
            
                content: [                    
                    // background
                    Rectangle {
                        layoutX: 0
                        layoutY: 0
                        width: bind this.width
                        height: bind this.height
                        fill: Color.web("#6E7180")
                    
                        onMouseMoved: function(e: MouseEvent): Void {
                            var state: StateInterface = StateFactory.getState();
                            if (state.getStateId() == StateInterface.STANDARD_STATE) {}
                            if (state.getStateId() == StateInterface.COMPONENT_STATE) {}
                            if (state.getStateId() == StateInterface.LINK_STATE) {}
                        }
                        onMouseClicked: function(e: MouseEvent) {
                            var state: StateInterface = StateFactory.getState();

                            if (state.getStateId() == StateInterface.STANDARD_STATE) {}
                            if (state.getStateId() == StateInterface.COMPONENT_STATE) {}
                            if (state.getStateId() == StateInterface.LINK_STATE) {}
                        }                        
                    },
                    ToolPanel {
                        layoutX: 10
                        layoutY: bind this.height - 150
                        width: bind this.width - 20
                        height: 150
                    }
                ]                
            }
    }

    override public function update(): Void {        
    }

    public function addViewComponent(viewComponent: ViewComponent): Void {
        if (viewComponent != null) {
            this.component.add(viewComponent.getComponent() as LLNode);
			insert viewComponent into this.mainPanel.content;
        }
    }

    public function removeViewComponent(viewComponent: ViewComponent): Void {
        if (viewComponent != null) {
			delete viewComponent from this.mainPanel.content;
			this.component.remove(viewComponent.getComponent() as LLNode);
		}
    }

    public function hasViewComponent(viewComponent: ViewComponent): Boolean {
        var value: Boolean = false;
        for (node in this.mainPanel.content) {
            if (node.equals(viewComponent)) {
                value = true;
                break;
            }
        }
        return value;
    }

	public function clearViewComponents(): Void {
		for (p in this.mainPanel.content) {
			if (p instanceof ViewComponent) {
				this.removeViewComponent(p as ViewComponent);
			}
		}
	}

    public function getViewComponentCoordinates(): Point2D {
        var point: Point2D = Point2D {
            x: this.viewComponentTranslateX
            y: this.viewComponentTranslateY
        }
        this.viewComponentTranslateX += 10;
        this.viewComponentTranslateY += 20;
        if (this.viewComponentTranslateY >= 500) {
            this.viewComponentTranslateY = 10.0;
        }
		if (this.viewComponentTranslateX >= 600) {
			this.viewComponentTranslateX = 10.0;
		}
        return point;
    }

	override public function saveToXML(): String {
		var xml: String;

		xml += "<?xml version=\"1.0\"?>\r\n";
		xml += "<ViewBox>\r\n";
		for (p in this.mainPanel.content) {
			if (p instanceof ViewComponent) {				
				xml += (p as ViewComponent).saveToXML();
			}
		}
		xml += "</ViewBox>";
		this.xml = xml;

		// output xml data to file
		var fos: FileOutputStream;
		var dos: DataOutputStream;

		try {
			var file: File = new File("llworkspace.xml");
			fos = new FileOutputStream(file);
			dos = new DataOutputStream(fos);
			dos.flush();
			dos.write(this.xml.getBytes());
		} catch (e: IOException) {
			e.printStackTrace();
		} finally {
			dos.close();
			fos.close();
		}

		return this.xml;
	}

	public function loadFromXML(xmlFile: String): Void {
		try {
			var file: File = new File(xmlFile);

			var dbf: DocumentBuilderFactory = DocumentBuilderFactory.newInstance();
			var db: DocumentBuilder = dbf.newDocumentBuilder();
			var doc: Document = db.parse(file);
			doc.getDocumentElement().normalize();			
			var docNodes: NodeList = doc.getElementsByTagName("ViewComponent");
			var linkNodes: Node[];

			for (i in [0..docNodes.getLength()]) {				
				var vc: ViewComponent = this.createViewComponent(docNodes.item(i));
				if (vc instanceof ViewLink) {
					insert docNodes.item(i) into linkNodes;
					// add link to the ViewBox later
					continue;
				}
				if (vc != null) {
					this.addViewComponent(vc);
					try {
						vc.getComponent().calculate();
					} catch (e: Exception) {}
				}
			}
			// create and add links
			for (link in linkNodes) {
				var viewLink: ViewComponent = this.createViewComponent(link);
				(viewLink as ViewLink).createLink();
				this.addViewComponent(viewLink);
			}
		} catch (e: Exception) {}
	}

	override public function loadFromXML(vcNode: Node): Void {
		throw new UnsupportedOperationException("Not supported.");
	}

	/*
	*	Used in loadFromXML(xmlFile: String)
	*
	*	If you can add new ViewComponent, then update this method
	*/
	function createViewComponent(vcNode: Node): ViewComponent {
		var viewComponent: ViewComponent = null;
		if (vcNode != null) {
			if (vcNode.getNodeType() == Node.ELEMENT_NODE) {
				var vcElement: Element = vcNode as Element;

				// get type
				var typeList: NodeList = vcElement.getElementsByTagName("Type");
				var typeElem: Element = typeList.item(0) as Element;
				var typeValue: String = typeElem.getChildNodes().item(0).getNodeValue();

				if (typeValue.equals("26")) {
					viewComponent = ViewMedian {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("1")) {
					viewComponent = ViewMiddleValue {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("4a")) {
					var viewLink: ViewLink = ViewLink {};
					var linkState: Integer = 0;
					
					viewLink.loadFromXML(vcNode);
					if (viewLink.getParent() != null) linkState += 1;
					if (viewLink.getChild() != null) linkState += 2;
					// not binding link to something
					if (linkState == 0) {
						viewComponent = ViewLink {
							startX: viewLink.startX
							startY: viewLink.startY
							endX: viewLink.endX
							endY: viewLink.endY
						};
					}
					// link's parent isn't null
					if (linkState == 1) {
						viewComponent = ViewLink {
							startX: bind viewLink.getParent().translateX
							startY: bind viewLink.getParent().translateY
							endX: viewLink.endX
							endY: viewLink.endY
						};
						(viewComponent as ViewLink).setParent(viewLink.getParent());
					}
					// link's child isn't null
					if (linkState == 2) {
						viewComponent = ViewLink {
							startX: viewLink.startX
							startY: viewLink.startY
							endX: bind viewLink.getChild().translateX
							endY: bind viewLink.getChild().translateY
						};
						(viewComponent as ViewLink).setChild(viewLink.getChild());
					}
					// link's child and parent isn't null
					if (linkState == 3) {
						viewComponent = ViewLink {
							startX: bind viewLink.getParent().translateX
							startY: bind viewLink.getParent().translateY
							endX: bind viewLink.getChild().translateX
							endY: bind viewLink.getChild().translateY
						};
						(viewComponent as ViewLink).setParent(viewLink.getParent());
						(viewComponent as ViewLink).setChild(viewLink.getChild());
					}
				}
				if (typeValue.equals("1a")) {
					viewComponent = ViewDummy {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("6")) {
					viewComponent = ViewAccuracyAssessment {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("10")) {
					viewComponent = ViewDifferenceBetween {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("7")) {
					viewComponent = ViewLeftBorder {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("8")) {
					viewComponent = ViewRightBorder {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("2")) {
					viewComponent = ViewSampleVariance {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("5")) {
					viewComponent = ViewStandardAMSError {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("3")) {
					viewComponent = ViewStandardDeviation {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("4")) {
					viewComponent = ViewVariationCoefficient {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("3a")) {
					viewComponent = ViewDotStudent {};
					viewComponent.loadFromXML(vcNode);
				}
				if (typeValue.equals("15")) {
					viewComponent = ViewIntervalBorders {};
					viewComponent.loadFromXML(vcNode);
				}
			}
		}		
		return viewComponent;
	}

	public function getMainPanel(): Panel {
		return this.mainPanel;
	}

}
